#ifndef CTAG_H
#define CTAG_H

#include <iostream>
#include <string.h>
#include <stdint.h>
#include <chrono>

//测点数据
class CTag
{
public:
    enum enumTagType
    {
        enUnknown,
        enUint8,
        enInt16,
        enUint16,
        enInt32,
        enUint32,
        enInt64,
        enUint64,
        enFloat,
        enDouble,
        enString,
    };

public:
    char        sAddr[128];         // 测点名称
    uint8_t     type;               // 测点数据类型（1字节）
    uint8_t     quality;            // 测点质量（1字节）
    //timespec timeStamp;           // 测点数据更新时戳（16字节）
    uint64_t    timeStamp;          // 测点数据更新时戳毫秒（8字节）
    uint16_t    dataSize;           // 数据长度（2字节）
    union {                         // 使用联合体存储不同类型的值
        uint8_t     byte;           // 布尔类型（1字节）
        int16_t     n16Num;         // 短整型（2字节）
        uint16_t    un16Num;        // 无符号短整型（2字节）
        int32_t     n32Num;         // 整型（4字节）
        uint32_t    un32Num;        // 无符号整型（4字节）
        int64_t     n64Num;         // 长整型（8字节）
        uint64_t    un64Num;        // 无符号长型（8字节）
        float       fNum;           // 单精度浮点型（4字节）
        double      dNum;           // 双精度浮点型（8字节）
        char*       str;            // 字符串首地址（4字节）
    } value;

    CTag()
    {
        memset(sAddr, 0, 128);
        type = enUnknown;
        timeStamp = getTimeStamp();
        dataSize = 0;
        value.dNum = 0;
    }

    CTag(const std::string &sAddr, const int &nType)
    {
        setAddr(sAddr);
        type = nType;
        timeStamp = getTimeStamp();
        dataSize = 0;
        value.dNum = 0;
    }

    CTag(const CTag &other)
    {
        memcpy(this, &other, sizeof(CTag));
        if(enString == type)
        {
            setDataSize(dataSize);
            memcpy(value.str, other.value.str, dataSize);
        }
    }

    virtual ~CTag()
    {
        if(enString == type)
        {
            if((0 < dataSize) && (nullptr != value.str))
                    delete[] value.str;
        }
    }

    uint8_t toUint8() { return value.byte; }
    int16_t toInt16() { return value.n16Num; }
    uint16_t toUint16() { return value.un16Num; }
    int32_t toInt32() { return value.n32Num; }
    uint32_t toUint32() { return value.un32Num; }
    int64_t toInt64() { return value.n64Num; }
    uint64_t toUint64() { return value.un64Num; }
    float toFloat() { return value.fNum; }
    double toDouble() { return value.dNum; }

    //获取时间戳
    static uint64_t getTimeStamp()
    {
		using namespace std::chrono;

		// 获取当前时间点（自 Unix 纪元以来）
		auto now = system_clock::now();

		// 转换为自 Unix 纪元以来的毫秒数
		auto duration = now.time_since_epoch();
		auto tStamp = duration_cast<milliseconds>(duration).count();

		return tStamp;
    }

    //设置地址
    int setAddr(const std::string &addr)
    {
        if(addr.size() >= 128) return -1;
        memset(sAddr, 0, 128);
        memcpy(sAddr, addr.c_str(), addr.size());
        return 0;
    }

    //字符串测点，设置长度
    int setDataSize(const int &nSize)
    {
        if(enString != type) return -1;
        if(128 < nSize) return -2;
        if(nSize < dataSize) return 0;
        //释放之前内存
        if(0 != dataSize)
        {
            delete[] value.str;
            value.str = nullptr;
        }
        dataSize = nSize;
        value.str = new char[nSize];
        memset(value.str, 0, dataSize);
        return 0;
    }

    //设置值
    void setValue(const double &val, const uint64_t &tStamp)
    {
        value.dNum = val;
        timeStamp = tStamp;
    }

    //设置值
    void setValue(const double &val)
    {
        value.dNum = val;
        timeStamp = getTimeStamp();
    }

    //设置值
    void setValue(const std::string &val)
    {
		timeStamp = getTimeStamp();
        if(enString != type) return;
        int nSize = val.size();
        if(128 < nSize) nSize = 128;
        setDataSize(nSize);
        memcpy(value.str, val.c_str(), nSize);
    }

    //设置值
    int setValue(const CTag &dest)
    {
        //if(0 == strcmp(sAddr, dest.sAddr)) return -1;
        type = dest.type;
        timeStamp = dest.timeStamp;
        if(enString != dest.type)
            value = dest.value;
        else
        {
            setDataSize(dest.dataSize);
            memcpy(value.str, dest.value.str, dataSize);
        }
        quality = dest.quality;
        return 0;
    }

    //设置值
    int setValue(const CTag* &dest)
    {
        if(0 == memcmp(sAddr, dest->sAddr, 128)) return -1;
        type = dest->type;
        timeStamp = dest->timeStamp;
        if(enString != dest->type)
            value = dest->value;
        else
        {
            setDataSize(dest->dataSize);
            memcpy(value.str, dest->value.str, dataSize);
        }
        return 0;
    }

    //获取值
    void getValue(double *val)
    {
        *val = value.dNum;
        return;

        switch (type) {
        case enUint8:
            *val = value.byte;
            break;
        case enInt16:
            *val = value.n16Num;
            break;
        case enInt32:
            *val = value.n32Num;
            break;
        case enUint32:
            *val = value.un32Num;
            break;
        case enInt64:
            *val = value.n64Num;
            break;
        case enUint64:
            *val = value.un64Num;
            break;
        case enFloat:
            *val = value.fNum;
            break;
        case enDouble:
            *val = value.dNum;
            break;
        case enUint16:
        default:
            *val = value.un16Num;
            break;
        }
    }

    //获取值
    void getValue(std::string &sVal)
    {
        sVal = value.str;
    }
};


#endif // CTAG_H
